package com.powergisol.gis.controller;

import com.powergisol.gis.service.FallBackService;
import com.powergisol.gis.service.IFileService;
import com.powergisol.gis.service.ProgressService;
import com.powergisol.gis.service.ServiceUploadService;
import com.powergisol.gis.util.FileList;
import com.powergisol.gis.util.FileUpload;
import com.powergisol.gis.util.PropertyUtil;
import com.powergisol.gis.util.Result;
import com.powergisol.gis.vo.TabServiceVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created By marc
 * Date: 2020/5/28  15:44
 * Description:
 */
@RestController
@Api(description = "服务上传管理(整体发布)" ,value = "服务上传管理(整体发布)")
public class UploadController {
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${collectionName}")
    private String collectionName;
//    @Value("${file-url}")
//    private String fileUrl;
    @Value("${expira_time}")
    private Integer expiraTime;
    @Autowired
    private ServiceUploadService serviceUploadService;
    @Autowired
    private FallBackService fallBackService;
    @Autowired
    private ProgressService progressService;
    @Autowired
    private IFileService fileService;

    /**
     * 数据上传
     * @param file 数据上传
     * @return
     */
    @GetMapping("wholeReleaseService")
    @ApiOperation(value = "数据上传", notes = "数据上传")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "MultipartFile", name = "file", value = "文件(本地上传)", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "fileUrl", value = "路径(服务器上传)", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "serviceType", value = "服务类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "assinSuffixName", value = "后缀名", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "codeType", value = "字符编码", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "changeType", value = "osgb指定转换类型（表b3dm、lob、pld）", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "isCut", value = "是否切片(1是)", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "currentUserId", value = "当前用户id", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "currentUserName", value = "当前用户名（与用户id必传一个）", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "type", value = "数据类型(数据类型id)", defaultValue = "8", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "dataPath", value = "数据路径", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "name", value = "服务名称", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "title", value = "服务标题", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "keyword", value = "关键字", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "description", value = "描述", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "zipUrl", value = "压缩文件路径", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "uuid", value = "uuid标识", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "startLevel", value = "高程转换顶层层级", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "endLevel", value = "高程转换底层层级", defaultValue = "0", required = true, paramType = "query")
    })
    public Result wholeReleaseService(MultipartFile file, TabServiceVo vo) throws Exception{
        Result result = new Result();
        if(redisTemplate.hasKey(vo.getName())){
            redisTemplate.delete(vo.getName());
            return result.failure(-1,"服务名称重复");
        }
        result = fallBackService.remoteServiceNameDouble(vo.getName());
        if(Integer.valueOf(result.getData().toString())>0){
            redisTemplate.delete(vo.getName());
            return result.failure(-1,"服务名称重复");
        }
        redisTemplate.opsForValue().set(vo.getName(),vo.getName());
        String userDir = System.getProperty("user.dir");
        userDir = userDir.substring(0,userDir.lastIndexOf(File.separator));
        //上传、解压、转换操作
        if(null != file){
            result = FileUpload.fileUpload(file,userDir+File.separator+"serviceData",vo);
            Map<String,Object> map = (Map<String,Object>)result.getData();
            serviceUploadService.unZiphThread(map,vo);
        }else{
            if(1!=vo.getServiceType() && 4!=vo.getServiceType()){
                String path = vo.getFileUrl();
                File fileService = new File(path);
                if(fileService.isFile() && 3!=vo.getServiceType()){
                    path = path.substring(0, path.lastIndexOf(File.separator));
                    if(6 == vo.getServiceType() && "pld".equals(vo.getChangeType())){
                        if(path.contains(".")){
                            redisTemplate.delete(vo.getName());
                            return result.failure(-3, "文件路径不能含有 . 字符");
                        }
                    }
                }
            }
            serviceUploadService.selectFileSave(vo,result);
        }
        //相应进度获取
        String uuid = vo.getUuid();
        Integer serviceType = vo.getServiceType();
        String changeType = vo.getChangeType();
        String name = vo.getName();
        String startLevel = vo.getStartLevel();
        if(result.getCode()==0){
            BigDecimal unzipProgress = BigDecimal.ZERO;
            Double changeProgress = 0d;
            while(true){
                TimeUnit.SECONDS.sleep(30);//秒
                //解压进度
                unzipProgress = null != redisTemplate.opsForValue().get(uuid+"UnzipProgress")?new BigDecimal(redisTemplate.opsForValue().get(uuid + "UnzipProgress").toString()):BigDecimal.ZERO;
                if(unzipProgress.compareTo(new BigDecimal("-1"))==0){
                    redisTemplate.delete(vo.getName());
                    return result.failure(-1,uuid+"解压异常");
                }
              //转换进度
                changeProgress = null!=redisTemplate.opsForValue().get(uuid + "ExchangeProgress")?Double.valueOf(redisTemplate.opsForValue().get(uuid + "ExchangeProgress").toString()):0d;
                if(changeProgress == -1){
                    redisTemplate.delete(vo.getName());
                    return result.failure(-1,uuid+"获取文件失败");
                }
                //转换为1或-1则无需调用转换速度接口
                if(changeProgress !=1 && unzipProgress.compareTo(new BigDecimal("100"))==0){
                    switch (serviceType){
                        case 6:
                            if(redisTemplate.hasKey(uuid+"In")&&redisTemplate.hasKey(uuid+"Out")){
                                String in = (String)redisTemplate.opsForValue().get(uuid+"In");
                                String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                                if("pld".equals(changeType)){
                                    out = out+ in.substring(in.lastIndexOf(File.separator),in.length());
                                    // logger.info("Osgb2Pld转换输入in={},out={}",in,out);
                                    try{
                                        changeProgress = progressService.osgb2Pld(uuid,in,out);
                                        // changeProgress = changeMapService.osgb2Pld(in,out);
                                        // logger.info("Osgb2Pld转换进度={}",changeProgress);
                                    }catch (Exception e){
                                        result.setCode(405);
                                    }
                                }else if("b3dm".equals(changeType)){
                                    //logger.info("Osgb2b3dm转换输入in={},out={}",in,out);
                                    try{
                                        // changeProgress = changeMapService.progressOsgb2b3dm(in,out);
                                        changeProgress = progressService.osgb2b3dm(uuid,in,out);
                                    }catch (Exception e){
                                        result.setCode(405);
                                    }
                                }
                            }
                            break;
                        case 7:
                            if(redisTemplate.hasKey(uuid+"In")&&redisTemplate.hasKey(uuid+"Out")){
                                String in = (String)redisTemplate.opsForValue().get(uuid+"In");
                                String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                                try{
                                    changeProgress = progressService.objToGltf(uuid,in.substring(0,in.lastIndexOf(File.separator)),out.substring(0,out.lastIndexOf(File.separator)));
//                            changeProgress = changeMapService.
//                                    progressObjToGltf(in.substring(0,in.lastIndexOf(File.separator)),out.substring(0,out.lastIndexOf(File.separator)));
                                }catch (Exception e){
                                    result.setCode(405);
                                }
                            }
                            break;
                        case 3:
                            if("terrain".equals(changeType)){
                                if(redisTemplate.hasKey(uuid+"Out")){
                                    String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                                    //logger.info("Tif2terrain转换输出out={}",out);
                                    try{
                                        changeProgress = progressService.tif2terrain(uuid,startLevel,out);
                                        //changeProgress = changeMapService.progressTif2terrain(startLevel,out);
                                    }catch (Exception e){
                                        result.setCode(405);
                                    }
                                }
                            }else{
                                changeProgress = 1d;
                            }
                            break;
                        default:
                            changeProgress = 1d;
                            break;
                    }
                }
                if(changeProgress==1 && unzipProgress.compareTo(new BigDecimal("100"))==0){
                    break;
                }
            }
            //调用保存入数据库
            if(changeProgress==1 && unzipProgress.compareTo(new BigDecimal("100"))==0){
                //5、读取转换后文件
                String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                //logger.info("{}转换后保存入库输出文件：{}",name,out);
                Map<String,Object> resultMap = null;
                switch (serviceType){
                    case 3:
                        if("terrain".equals(vo.getChangeType())){
                            try {
                                //文件转换json文件可能未生成，休眠30秒再读取
                                TimeUnit.SECONDS.sleep(30);//秒
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            result = FileList.fileRead(out,"json");
                            out = out+File.separator+"layer.json";
                            resultMap = (Map<String,Object>)result.getData();
                        }
                        break;
                    case 6:
                        try {
                            //文件转换json文件可能未生成，休眠30秒再读取
                            TimeUnit.SECONDS.sleep(30);//秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if("pld".equals(changeType)){
                            String in = (String)redisTemplate.opsForValue().get(uuid+"In");
                            out = out+ in.substring(in.lastIndexOf(File.separator),in.length());
                            result = FileList.fileRead(out,"json");
                            out = out + File.separator+"model.json";
                        }else if("b3dm".equals(changeType)){
                            result = FileList.fileRead(out,"json");
                            out = out+File.separator+"tileset.json";
                        }
                        resultMap = (Map<String,Object>)result.getData();
                        break;
                    case 7:
                        try {
                            //文件转换json文件可能未生成，休眠30秒再读取
                            TimeUnit.SECONDS.sleep(30);//秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // File file = new File(out);
                        result = FileList.fileRead(out.substring(0,out.lastIndexOf(File.separator)),"glb");
                        // out = out.substring(0, out.lastIndexOf(File.separator));
                        resultMap = (Map<String,Object>)result.getData();
                        break;
                }
                if(null!=resultMap && null != resultMap.get("listFile")){
                    // logger.info("{}转换后保存入库开始",name);
                    List<File> changeList = ( List<File>)resultMap.get("listFile");
                    redisTemplate.opsForValue().set(uuid+"TotalSize",changeList.size(),expiraTime,TimeUnit.HOURS);  //6、保存入库
                    serviceUploadService.saveFileToDb(changeList,uuid,name,out.replace("/",File.separator));
                    resultMap.remove("listFile");
                }
            }
            //保存进度
            while (true){
                TimeUnit.SECONDS.sleep(30);//秒
                //总的条数
                BigDecimal totalSize = null!=redisTemplate.opsForValue().get(uuid + "TotalSize")?new BigDecimal(redisTemplate.opsForValue().get(uuid + "TotalSize").toString()):BigDecimal.ZERO;
                BigDecimal progress = BigDecimal.ZERO;
                BigDecimal savedSize = BigDecimal.ZERO;
                if(totalSize.compareTo(BigDecimal.ZERO)>0){
                    String prefix = uuid+"SavedFile*";
                    Set<String> keys = redisTemplate.keys(prefix);
                    for(String key : keys){
                        savedSize = savedSize.add(new BigDecimal(redisTemplate.opsForValue().get(key).toString()));
                    }
                    progress = savedSize.divide(totalSize,2,BigDecimal.ROUND_DOWN).multiply(new BigDecimal(100));
                }else{
                    progress =  null!=redisTemplate.opsForValue().get(uuid + "SaveProgress")?new BigDecimal(redisTemplate.opsForValue().get(uuid + "SaveProgress").toString()):BigDecimal.ZERO;
                }
                if(progress.compareTo(new BigDecimal("100"))==0){
                    break;
                }
            }
            //获取fileUrl
            if(1 != serviceType && 4 != serviceType && !(3==serviceType && ("terrain").equals(changeType))){//tif和shp不会转换跳过
                try {
                    //文件转换json文件可能未生成，休眠30秒再读取
                    TimeUnit.SECONDS.sleep(10);//秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
            String in = (String)redisTemplate.opsForValue().get(uuid+"In");
            switch (serviceType){
                //注：shp文件获取点线面的样式需要修改
                case 6:
                    if("pld".equals(changeType)){
                        out = out+ in.substring(in.lastIndexOf(File.separator),in.length())+File.separator+"model.json";
                    }else if("b3dm".equals(changeType)){
                        out = out+File.separator+"tileset.json";
                    }
                    break;
                case 3:
                    if("terrain".equals(changeType)){
                        out = out+File.separator+"layer.json";
                        break;
                    }
                    break;
            }
            if(4 != serviceType){
                File  fileUrl = new File(out);
                String filename = file.getName();
                String suffix = filename.substring(filename.lastIndexOf(".") + 1);
                List<File> fileList = new ArrayList<>();
                fileList.add(fileUrl);
                fileService.importFilesToFs(fileUrl,uuid+fileUrl.getAbsolutePath(),suffix,uuid);
            }
            //保存服务
            vo.setFileUrl(out);
            vo.setOriginUrl(in);
            result = fallBackService.remoteReleaseTabService(vo.getServiceType(),vo.getChangeType(),vo.getAssinSuffixName(),
                    vo.getCurrentUserId(),vo.getCurrentUserName(),vo.getName(),vo.getType(),vo.getKeyword(),vo.getDescription(),
                    vo.getFileUrl(),vo.getStartLevel(),vo.getEndLevel(),vo.getUuid());
            redisTemplate.delete(vo.getName());
            return result;
        }
        return result;
    }
}
